package com.utility.project.common.utils;



import com.utility.project.config.DataAuthInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalTime;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 滑动窗口限流算法工具类
 */
@Slf4j
public class SlideWindowLimitUtils {

    private static Logger logger = LoggerFactory.getLogger(SlideWindowLimitUtils.class);

    private volatile static Map<String, List<Long>> limitMap = new ConcurrentHashMap<>();

    private SlideWindowLimitUtils() {

    }

    /**
     * 在指定的时间窗口，指定限制次数内，是否允许通过
     *
     * @param requestMethod
     * @param count
     * @param allowTime
     * @return
     */
    public static synchronized boolean checkLimit(String requestMethod, int count, long allowTime) {
        long currentTime = System.currentTimeMillis();
        //根据请求方法名，找出对应的限流队列
        List<Long> limitList = limitMap.computeIfAbsent(requestMethod, k -> new LinkedList<>());
        //如果队列还没满，则允许通过，并将当前时间添加到限流队列最开始(采用头插法，每次的数据都插入到第一个)
        if (limitList.size() < count) {
            limitList.add(0, currentTime);
            return true;
        }
        //如果请求方法已经到达限流次数，则获取最早添加的时间戳数据
        Long earliestTime = limitList.get(count - 1);
        if (currentTime - earliestTime <= allowTime) {
            logger.error("{}方法请求速度太过频繁，请稍后再试！", requestMethod);
            return false;
        } else {
            //否则把最早请求的时间戳删除，把最新请求的时间戳放在最开始位置
            limitList.remove(count - 1);
            limitList.add(0, currentTime);
            logger.info("{}方法允许通行，请求时间为{}", requestMethod, LocalTime.now());
            return true;
        }
    }

}
